import axios from "axios";
import compareObj from "@/assets/js/compare.js";
import message from "@/components/_message/src/message.js";

const { isObject, isArray } = compareObj;
const config = {
  baseUrl: {
    dev: "",
    pro: "",
  },
};
const baseUrl =
  process.env.NODE_ENV === "development"
    ? config.baseUrl.dev
    : config.baseUrl.pro;

function toString(data, includeName) {
  return Object.prototype.toString.call(data).includes(includeName);
}

const CancelToken = axios.CancelToken;
const storeKey = "cache_api_data";
const apiCache = Object.create(null);
const cacheTimer = Object.create(null);
// localStorage.apiProxy 为apiCache开关
const isUseLocalStorageCacheData = localStorage.apiProxy;
const isUseCacheData = true;
if (isUseLocalStorageCacheData) {
  message.warning("注意前端开启了数据缓存, 已缓存数据不会从后端获取!");
  let _storeData = localStorage[storeKey] || "{}";
  let data = JSON.parse(_storeData);
  Object.entries(data).forEach(([key, data]) => {
    apiCache[key] = data;
  });
}

let needClearCache = false;
function startClearCahe() {
  if (!needClearCache) {
    needClearCache = true;
    loopClearCache();
  }
}

const cacheValidDuration = 30 * 1000; //30s
const loopInterval = cacheValidDuration / 3;
function loopClearCache() {
  if (isUseLocalStorageCacheData) {
    return;
  }

  const timer = setInterval(() => {
    const now = Date.now();
    const list = Object.entries(cacheTimer);
    for (let [key, value] of list) {
      if (now - value > cacheValidDuration) {
        delete cacheTimer[key];
        delete apiCache[key];
      }
    }

    if (list.length === 0) {
      clearInterval(timer);
    }
  }, loopInterval);
}

function getCacheKey({ url, data, params }) {
  let queryParams = data || params;
  if (typeof queryParams === "object") {
    queryParams = JSON.stringify(queryParams);
  }

  return url + "#" + queryParams;
}

const needCheckResponseQuery = [];
function waitServerResponse(cacheKey) {
  return new Promise((resolve) => {
    needCheckResponseQuery.push({ cacheKey, resolve });
  });
}

function processWaitQuery() {
  const needDeleteQueryIndex = [];
  needCheckResponseQuery.forEach((item, index) => {
    const { cacheKey, resolve } = item;
    const cacheData = apiCache[cacheKey];
    if (cacheData) {
      resolve(cacheData);
      needDeleteQueryIndex.push(index); //TD: check if this can cause dead loop
    }
  });

  needDeleteQueryIndex.forEach((n) => needCheckResponseQuery.splice(n, 1));
}

//后端要求: 过滤请求参数值为空的参数
function filterRequestData(requestData) {
  if (isArray(requestData)) {
    requestData.forEach((item) => filterRequestData(item));
  } else if (isObject(requestData)) {
    Object.keys(requestData).forEach((key) => {
      let value = requestData[key];
      if (typeof requestData[key] === "string") {
        value = value.trim();
        if (value === "") {
          Reflect.deleteProperty(requestData, key);
        }
      } else if (isObject(value) || isArray(value)) {
        filterRequestData(value);
      }
    });
  }

  return requestData;
}

function cancelRequest(data, config) {
  let source = CancelToken.source();
  config.cancelToken = source.token;
  source.cancel(data);
}
// console.log('filterRequestData=====')
// console.log(filterRequestData({ a: 123, b: [{ name: '', age: 11, children: [{ name: '' }] }] }))

class HttpRequest {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
  }
  getInsideConfig() {
    let parentVuex = (window.__instance && window.__instance.parentVuex) || {
      state: {},
    };
    let userName = parentVuex.state.userName;
    let umAccount = parentVuex.state.umAccount || "";
    if (process.env.NODE_ENV === "development") {
      umAccount = "GENGPENGPENG950";
    }

    const _config = {
      baseURL: this.baseUrl,
      headers: {
        "X-TJE-USER": umAccount,
        "SET-ID": parentVuex.state.companyId || "SZDBK",
        "X-TJE-USER-NAME": userName ? encodeURIComponent(userName) : "",
        Pragma: "no-cache",
        "X-Requested-With": "XMLHttpRequest",
      },
      // 返回true, 响应拦截器不会执行错误拦截，统一执行resolve
      validateStatus: () => true,
    };
    return _config;
  }

  interceptors(instance) {
    // 添加请求拦截器
    instance.interceptors.request.use(
      async function (config) {
        config.data = filterRequestData(config.data);
        if (isUseCacheData) {
          const cacheKey = getCacheKey(config);
          let data = apiCache[cacheKey];
          if (data) {
            cancelRequest(data, config);
          } else if (cacheKey in apiCache) {
            data = await waitServerResponse(cacheKey);
            cancelRequest(data, config);
          } else {
            apiCache[cacheKey] = "";
          }
        }

        return config;
      },
      function (error) {
        // 对请求错误做些什么
        return Promise.reject(error);
      }
    );

    // 添加响应拦截器
    instance.interceptors.response.use(
      function (response) {
        let { status, data } = response;
        if (status == 200) {
          // response.data 是文件流的排除掉，比如导出功能
          // 9xx 业务编码错误，与后端约定
          if (
            data.code === "200" ||
            Number(data.code) >= 900 ||
            toString(response.data, "Blob")
          ) {
            if (isUseCacheData) {
              const { config } = response;
              const cacheKey = getCacheKey(config);
              apiCache[cacheKey] = { data };
              cacheTimer[cacheKey] = Date.now();
              startClearCahe();
              processWaitQuery();
              if (isUseLocalStorageCacheData) {
                try {
                  localStorage[storeKey] = JSON.stringify(apiCache);
                } catch (error) {
                  console.error(
                    "[Data Cache]: Set localstorage data error: ",
                    error
                  );
                }
              }
            }
            return data;
          } else {
            return Promise.reject(data);
          }
        } else if (
          status === 308 &&
          process.env.VUE_APP_IS_DEVELOPMENT === "false"
        ) {
          window.__instance.parentVuex.commit("changLogin", false);
          window.__instance.parentVuex.commit("changeHasAuthed", false);
          window.__instance.parentVuex.commit("setUserName", "");
          window.__instance.parentVuex.commit("setUmAccount", "");

          console.log("location.href---", window.location.href);
          window.location.href =
            window.location.href.split("/tje/")[0] + "/caslogout";

          return null;
        }

        return Promise.reject(response);
      },
      function (error) {
        // 对响应错误做点什么
        const resData = error?.message?.data;
        if (isUseCacheData && resData) {
          console.log("Use cached data!");
          return Promise.resolve(resData);
        }
        return Promise.reject(error);
      }
    );
  }
  _getRequest(url, params = {}) {
    var _options = {
      ...this.getInsideConfig(),
      method: "get",
      ...{ url: url, params },
    };
    const instance = axios.create();
    this.interceptors(instance);
    return instance(_options);
  }

  _postRequest(url, params = {}, headConfig = {}) {
    var _options = {
      ...this.getInsideConfig(),
      method: "post",
      ...headConfig,
      url: url,
      data: params,
    };
    const instance = axios.create();
    this.interceptors(instance);
    return instance(_options);
  }

  /**
   * 对外暴露的方法
   * @param {*} url
   * @param {*} params
   */
  getHttp(url, params = {}) {
    return new Promise((resolve, reject) => {
      this._getRequest(url, params)
        .then((res) => {
          resolve(res);
        })
        .catch((error) => {
          errorHandle(error, reject);
        });
    });
  }

  /**
   * 对外暴露的方法
   * @param {*} url
   * @param {*} params
   */
  postHttp(url, params = {}, headConfig = {}) {
    return new Promise((resolve, reject) => {
      this._postRequest(url, params, headConfig)
        .then((res) => {
          resolve(res);
        })
        .catch((error) => {
          errorHandle(error, reject);
        });
    });
  }
}

function errorHandle(error, reject) {
  // status 是http请求状态码，code 请求成功，业务处理状态码
  let err = { status: 200, ...error };
  if (error.status && error.statusText) {
    // response 返回的 reject, status !== 200,308
    err = { status: error.status, code: error.status, msg: error.statusText };
  } else if (error.name === "Error") {
    err.msg = error.message;
  }
  reject({ ...err });
}

export default new HttpRequest(baseUrl);
